package com.tianchi.lexiang.socketclient;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.tianchi.lexiang.bean.LeXiangConstants;
import com.tianchi.lexiang.bean.OriginalAccompany;
import com.tianchi.lexiang.bean.VolumeValueRecord;
import com.tianchi.lexiang.constant.Commands;
import com.tianchi.lexiang.service.GetAlreadyPointNums;
import com.tianchi.lexiang.util.AlreadyPointUtil;
import com.tianchi.lexiang.util.DatabaseVersionUtil;
import com.tianchi.lexiang.util.SongsClickRateUtil;
import com.tianchi.lexiang.util.SyncTableUtil;

public class SocketProcesser extends Handler {
	private static final String TAG = "SocketProcesser";
	private Context mContext;
	private static SocketProcesser instance ;
	
	public static final int SYNC_DB_OVER = 100231;
	
	private SyncTableUtil syncTableUtil ;
	private Heart mHeart = new Heart();
	private Timeout mTimeout = new Timeout();
	private List<SocketProcesserCallBack> mCallBacks = new ArrayList<SocketProcesser.SocketProcesserCallBack>();
	
	private AlreadyPointUtil alreadyPointUtil ;
	private SongsClickRateUtil clickRateUtil ;
	private GetAlreadyPointNums numInstence ;
	
	private void initSqlUtil(){
		Log.d(TAG, "[initSqlUtil]...");
//		sqlOper = DBOperator.getInstance().getConnection();
		syncTableUtil = SyncTableUtil.getInstence();
		alreadyPointUtil = AlreadyPointUtil.getInstence();
		numInstence = GetAlreadyPointNums.getInstence();
		clickRateUtil = SongsClickRateUtil.getInstence();
	}
	
	public SocketProcesser(Context mContext) {
		super();
		this.mContext = mContext;
		instance = this;
		postDelayed(mHeart, 10 * 1000);;
	}

	public static SocketProcesser getSocketProcesser(){
		return instance;
	}
	
	@Override
	public void handleMessage(Message msg) {
		super.handleMessage(msg);
		if (msg.what == SYNC_DB_OVER) {
			String serverDBVersion = DatabaseVersionUtil.getRecordServerDBVersion();
			Log.d(TAG, "[handleMessage]...===>" + serverDBVersion);
			DatabaseVersionUtil.persistDBVersion(mContext, serverDBVersion);
			initSqlUtil();
			Log.d(TAG, "[handleMessage] SYNC_DB_OVER will initQueryUtils and dismissSyncDialog");
			if (mCallBacks.size() != 0) {
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.initQueryUtils();
					callback.dismissSyncDialog();
				}
			}
			GetAlreadyPointNums.getInstence().sendBroadcastUpdateAlreadyPointNumber(mContext);
            GetAlreadyPointNums.getInstence().sendBroadcastUpdateOsdSubTitle(mContext);
		}else {
			Commands cmdObj = (Commands) msg.obj;
			resolveCmd(cmdObj);
		}
	}
	
	public void registerCallBack(SocketProcesserCallBack mCallBack){
		int size = mCallBacks.size();
		boolean hasRegister = false;
		for (int i = 0; i < size; i++) {
			if (mCallBack == mCallBacks.get(i)) {
				Log.w(TAG,mCallBack +" has already register");
				hasRegister = true;
				break;
			}
		}
		if (!hasRegister) {
			mCallBacks.add(mCallBack);
		}
	}
	
	public void unRegisterCallBack(SocketProcesserCallBack mCallBack){
		int size = mCallBacks.size();
		for (int i = 0; i < size; i++) {
			if (mCallBack == mCallBacks.get(i)) {
				mCallBacks.remove(i);
				Log.d(TAG, "remove mCallBack");
				break;
			}
		}
	}
	
	private void resolveCmd(Commands cmd) {
		Log.d(TAG, "resolveCmd cmd =>" + cmd);
		String cmdType = cmd.getCmdType();
		String cmdContent = cmd.getCmdContent();
		Log.d(TAG, "resolveCmd cmdType =>" + cmdType + ";;cmdContent==>" +cmdContent);
		switch (Integer.parseInt(cmdType)) {
		case Commands.CMD_DB_TYPE:
			processDBCmd(cmdContent);
			break;
		case Commands.CMD_VIDEO_TYPE:
			processVideoCmd(cmdContent);
			break;
		case Commands.CMD_ORIGINAL_TYPE:
			processOriginalCmd(cmdContent);
			break;
		case Commands.CMD_VOLUME_TYPE:
			processVolumeCmd(cmdContent);
			break;
		case Commands.CMD_SYNC_DB:
			processSyncDB(cmdContent);
			break;
		case Commands.CMD_HEART_RESONSE:
			processHeartResonse(cmdContent);
			break;
		case Commands.CMD_SYNC_TABLE_ALREADYPOINT:
			processSyncAlreadyPoint(cmdContent);
			break;
		case Commands.CMD_SYNC_TABLE_PUBLIC_SONG:
			processSyncPublicSong(cmdContent);
			break;
		case Commands.CMD_SYNC_TABLE_OSD:
			processSyncOsd(cmdContent);
			break;
		case Commands.CMD_DB_ADD:
			processAlreadyAdd(cmdContent);
			break;
		case Commands.CMD_DB_DELETE:
			processAlreadyDelete(cmdContent);
			break;
		case Commands.CMD_DB_TOP:
			processAlreadyTop(cmdContent);
			break;
		case Commands.CMD_DB_PRIORITY:
			processAlreadyPriority(cmdContent);
			break;
		case Commands.CMD_BACKGROUND:
			processBackgroundCmd(cmdContent);
			break;
		case Commands.CMD_RESET_PWD:
			resetPwdCmd(cmdContent);
			break;
		case Commands.CMD_QUERY_VERSION:
			persistServerDBVersion(cmdContent);
			break;
		default:
			break;
		}
	}
	
	private void processAlreadyAdd(String cmdContent) {
		Log.d(TAG, "[processAlreadyAdd] cmdContent=>"+cmdContent);
		String[] arr = cmdContent.split(",");
		if (arr.length == 2) {
			int songId = Integer.parseInt(arr[0]);
			String songName = arr[1];
			if (alreadyPointUtil.insertAlreadyPointSong(LeXiangConstants.DEMAND,
					songId, songName)) {
				numInstence.sendBroadcastUpdateAlreadyPointNumber(mContext);
				numInstence.sendBroadcastUpdateOsdSubTitle(mContext);
				clickRateUtil.setSongsClickRate(songId); 
				if (mCallBacks.size() != 0) {
					for (SocketProcesserCallBack callback : mCallBacks) {
						callback.refreshUI();
					}
				}
			}
		}
	}
	private void processAlreadyTop(String cmdContent) {
		Log.d(TAG, "[processAlreadyTop] cmdContent=>"+cmdContent);
		String[] arr = cmdContent.split(",");
		if (arr.length == 2) {
			int songId = Integer.parseInt(arr[0]);
			int orderId = Integer.parseInt(arr[1]);
			if (alreadyPointUtil.setAlreadyPointSongToTop(songId, orderId)) {
				numInstence.sendBroadcastUpdateOsdSubTitle(mContext);
				if (mCallBacks.size() != 0) {
					for (SocketProcesserCallBack callback : mCallBacks) {
						callback.refreshUI();
					}
				}
			}
		}
	}
	
	private void processAlreadyDelete(String cmdContent) {
		Log.d(TAG, "[processAlreadyDelete] cmdContent=>"+cmdContent);
		String[] arr = cmdContent.split(",");
		if (arr.length == 2) {
			int songId = Integer.parseInt(arr[0]);
			int orderId = Integer.parseInt(arr[1]);
			Log.d(TAG, "[processAlreadyDelete]   songId==>"+songId);
			Log.d(TAG, "[processAlreadyDelete]   orderId==>"+orderId);
			if (orderId == 0 || songId == 0) {
				Log.e(TAG, "[processAlreadyDelete] songId is 0 ,return");
				return;
			}
			if (alreadyPointUtil.deleteAlreadyPointSong(songId, orderId)) {
				numInstence.sendBroadcastUpdateAlreadyPointNumber(mContext);
				numInstence.sendBroadcastUpdateOsdSubTitle(mContext);
				if (mCallBacks.size() != 0) {
					for (SocketProcesserCallBack callback : mCallBacks) {
						callback.refreshUI();
					}
				}
			}
		}
	}
	
	private void processAlreadyPriority(String cmdContent) {
		Log.d(TAG, "[processAlreadyPriority] cmdContent=>"+cmdContent);
		String[] arr = cmdContent.split(",");
		if (arr.length == 2) {
			int songId = Integer.parseInt(arr[0]);
			String songName = arr[1];
			if (alreadyPointUtil.insertAlreadyPointSong(
					LeXiangConstants.PERVIEW, songId, songName)) {
				clickRateUtil.setSongsClickRate(songId);
				numInstence.sendBroadcastUpdateAlreadyPointNumber(mContext);
				numInstence.sendBroadcastUpdateOsdSubTitle(mContext);
				if (mCallBacks.size() != 0) {
					for (SocketProcesserCallBack callback : mCallBacks) {
						callback.refreshUI();
					}
				}
			}
		}
	}
	
	private void processSyncOsd(String cmdContent) {
		Log.d(TAG, "already point table synchronous");
		syncTableUtil.syncOsdSubtitleTable(cmdContent);
		GetAlreadyPointNums.getInstence().sendBroadcastUpdateOsdSubTitle(mContext);
	}

	private void processSyncPublicSong(String cmdContent) {
		Log.d(TAG, "public song synchronous");
		syncTableUtil.syncPublicSongTable(cmdContent);
		Log.d(TAG, "[processSyncPublicSong] sync with server is over dismiss sync dialog");
		if (mCallBacks.size() != 0) {
			for (SocketProcesserCallBack callback : mCallBacks) {
				callback.dismissSyncDialog();
			}
		}
	}

	private void processSyncAlreadyPoint(String cmdContent) {
		Log.d(TAG, "[processSyncAlreadyPoint]osd subtitles table synchronous");
		initSqlUtil();
		if (mCallBacks.size() != 0) {
			for (SocketProcesserCallBack callback : mCallBacks) {
				callback.initQueryUtils();
			}
		}
		syncTableUtil.syncAlreadyPointTable(cmdContent);
		GetAlreadyPointNums.getInstence().sendBroadcastUpdateAlreadyPointNumber(mContext);
	}

	private void processHeartResonse(String cmdContent){
		Log.d(TAG, "processHeartResonse  cmdContent==>"+cmdContent);
		removeCallbacks(mTimeout);
	}
	
	private void processDBCmd(String cmdContent){
		Log.d(TAG, "processDBCmd  cmdContent==>"+cmdContent);
//		sqlOper.rawQuery(cmdContent, null);
	}
	
	private void processSyncDB(String cmdContent){
		String version = cmdContent;
		Log.d(TAG, "[processSyncDB] server db version ==>"+cmdContent);
		DatabaseVersionUtil.recordServerDBVersion(version);
		Socket mSocket;
		try {
			mSocket = new Socket(SocketConnectUtil.SERVER_IP, SocketConnectUtil.SERVER_PORT);
			new Thread(new SocketDBReceiver(mSocket, mContext, this)).start();
		} catch (UnknownHostException e) {
			e.printStackTrace();
			Log.e(TAG, "UnknownHostException",e);
		} catch (IOException e) {
			e.printStackTrace();
			Log.e(TAG, "IOException",e);
		}
	}
	
	private void processVideoCmd(String cmdContent){
		int videoDetailCmd = Integer.parseInt(cmdContent);
		switch (videoDetailCmd) {
		case Commands.VIDEO_LOOP:
			Log.d(TAG, "processVideoCmd  VIDEO_LOOP");
			break;
		case Commands.VIDEO_NEXT:
			Log.d(TAG, "processVideoCmd  VIDEO_NEXT");
			if (alreadyPointUtil.getAlreadyPointSongsCount() >= 1) {
				alreadyPointUtil.cutSong();
				numInstence.sendBroadcastUpdateAlreadyPointNumber(mContext);
				numInstence.sendBroadcastUpdateOsdSubTitle(mContext);
			}
			if (mCallBacks.size() != 0) {
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.refreshUI();
				}
			}
			break;
		case Commands.VIDEO_PAUSE:
			Log.d(TAG, "processVideoCmd  VIDEO_PAUSE");
			if (mCallBacks.size() != 0) {
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.changeMediaStartPause(true);
				}
			}
			break;
		case Commands.VIDEO_START:
			Log.d(TAG, "processVideoCmd  VIDEO_START");
			if (mCallBacks.size() != 0) {
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.changeMediaStartPause(false);
				}
			}
			break;
		default:
			break;
		}
		Log.d(TAG, "we just socket client,needn't response video cmd");
	}
	
	private void processOriginalCmd(String cmdContent){
		
		Log.d(TAG, "[processOriginalCmd]....cmdContent==>"+ cmdContent);
		int originalCmd = Integer.parseInt(cmdContent);
		switch (originalCmd) {
		case Commands.ORIGINAL:
			if(mCallBacks.size() != 0){
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.setOriginalSinger(false);
				}
			}
			break;
		case Commands.ACCOMPANY:
			if(mCallBacks.size() != 0){
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.setOriginalSinger(true);
				}
			}
				break;
			default:
				break;
		}
		OriginalAccompany.getInstance().setVolumeState(originalCmd);
	}
	
	private void processVolumeCmd(String cmdContent){
		int volumeCmd = Integer.parseInt(cmdContent);
		AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
		audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
				volumeCmd, 0);
		VolumeValueRecord.getInstance().setVolumeValue(volumeCmd);
		if (mCallBacks.size() != 0) {
			for (SocketProcesserCallBack callback : mCallBacks) {
				if (volumeCmd == 0) {
					callback.setMute(false);
				} else {
					callback.setMute(true);
				}
			}
		}
	}
	
	private void processBackgroundCmd(String cmdLoginStatus){
		numInstence.sendBroadcastBackgroundLogin(mContext, cmdLoginStatus);
	}
	
	private void resetPwdCmd(String cmdResetPwd){
		numInstence.sendBroadcastBackgroundLogin(mContext, cmdResetPwd);
	}
	
	private void persistServerDBVersion(String serverDBVersion){
//		int version = Integer.parseInt(serverDBVersion);
		DatabaseVersionUtil.persistDBVersion(mContext, serverDBVersion);
	}
	
	private class Heart implements Runnable{
		@Override
		public void run() {
			Log.d(TAG, "send Heart to server");
			Commands cmdObj = new Commands(Commands.CMD_HEART, -1);
			try {
				SocketConnectUtil.getSocketConnectUtil().sendSocket(cmdObj.translateToDetailCmd());
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			//this is a timer , if 3s later the timer hasn't been cancel ,that means we
			//have disconnect with the server
			postDelayed(mTimeout, 3 * 1000);
			postDelayed(mHeart, 10 * 1000);
		}
	}
	
	private class Timeout implements Runnable{
		@Override
		public void run() {
			Log.e(TAG, "server can't response ,we disconnect server");
			try {
				SocketConnectUtil.getSocketConnectUtil().disconnect();
			} catch (UnknownHostException e) {
				Log.d(TAG, "[Timeout]",e);
				e.printStackTrace();
			} catch (IOException e) {
				Log.d(TAG, "[Timeout]",e);
				e.printStackTrace();
			}
			removeCallbacks(mHeart);
			removeCallbacks(mTimeout);
			if (mCallBacks.size() != 0) {
				for (SocketProcesserCallBack callback : mCallBacks) {
					callback.showDisConnectDialog();
				}
			}else {
				Log.e(TAG, "mCallBacks is null,please check it");
			}
		}
	}
	
	public void clearHeart(){
		removeCallbacks(mHeart);
		removeCallbacks(mTimeout);
	}
	
	public interface SocketProcesserCallBack{
		public void showDisConnectDialog();

		public void dismissSyncDialog();

		public void changeMediaStartPause(boolean checked);

		public void refreshUI();

		public void setMute(boolean isMute);
		
		public void setOriginalSinger(boolean isChecked);
		
		public void initQueryUtils();
	}
}
